﻿using Consul;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using static M.Core.ClientEventMgr;
using static M.Core.RmoteCall.RpcCall.RpcServiceInfo;

namespace M.Core.RmoteCall.RpcCall
{
    public class RpcServiceKeeper : IServiceChange
    {
        private static RpcServiceKeeper rpcModelKeeper = null;
        private static object lockObj = new object();
        private RpcServiceKeeper()
        {
            ClientEventMgr.GetInstance().OnServiceChangeDelegate.Add(this);
        }
        public static RpcServiceKeeper GetInstance()
        {
            if (rpcModelKeeper==null)
            {
                lock (lockObj)
                {
                    if (rpcModelKeeper == null)
                    {
                        rpcModelKeeper = new RpcServiceKeeper();
                    }
                }
            }
            return rpcModelKeeper;
        }
        ConcurrentDictionary<string, RpcServiceInfo> map = new ConcurrentDictionary<string, RpcServiceInfo>();
        Dictionary<string, string> lockMap = new Dictionary<string, string>();


        public void Add(string serviceName,IPEndPoint iPEndPoints)
        {
            GetModel(serviceName,iPEndPoints);
        }

        public bool Remove(IPEndPoint iPEndPoint)
        {
            var key = iPEndPoint.ToString();

            if (map.TryGetValue(key, out RpcServiceInfo callModel))
            {
                try
                {
                    return map.TryRemove(key, out callModel);
                }
                finally
                {
                    callModel.Dispose();
                }
            }

            return false;
        }

        public void ReSet(CallSocketObject callSocketObject)
        {
            callSocketObject.SocketReset();
        }

        public RpcServiceInfo GetModel(string serviceName,IPEndPoint iPEndPoint)
        {
            var key = iPEndPoint.ToString();

        reTry:
            if (map.TryGetValue(key, out RpcServiceInfo callModel))
            {
                return callModel;
            }

            var lockStr = string.Empty;
            lockMap.TryGetValue(key, out lockStr);
            if (string.IsNullOrWhiteSpace(lockStr))
            {
                lock (lockMap)
                {
                    if (string.IsNullOrWhiteSpace(lockStr))
                    {
                        lockStr = key;
                        lockMap[key] = lockStr;
                    }
                }
            }

            lock (lockStr)
            {
                if (map.ContainsKey(key)) goto reTry;
                callModel = new RpcServiceInfo(iPEndPoint);
                callModel.Name = serviceName;
                callModel.Key = key;
                callModel.InitPool();
                map.TryAdd(key, callModel);
            }

            return callModel;
        }

        public void Notify(ChangeType changeType, CatalogService catalogService)
        {
            if (!catalogService.ServiceMeta.ContainsKey("ThriftPort")) return;

            var val = catalogService.ServiceMeta["ThriftPort"];
            int thriftPort = -1;
            if (!string.IsNullOrWhiteSpace(val)&& int.TryParse(val,out thriftPort))
            {
                IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(catalogService.ServiceAddress), thriftPort);
                switch (changeType)
                {
                    default:
                    case ChangeType.Add:
                        Add(catalogService.ServiceName, iPEndPoint);
                        break;
                    case ChangeType.Remove:
                        Remove(iPEndPoint);
                        break;
                    case ChangeType.ReBulidModel:
                        Remove(iPEndPoint);
                        Add(catalogService.ServiceName, iPEndPoint);
                        break;
                }
            }
        }
    }



}
